package com.manda.smart.hub.expression;

import cn.hutool.core.lang.Assert;
import cn.hutool.crypto.digest.DigestUtil;
import com.googlecode.aviator.*;
import com.manda.smart.hub.expression.extend.EnhancedFunctionLoader;
import com.manda.smart.hub.expression.extend.FunctionFallback;
import com.manda.smart.hub.expression.extend.FunctionScanner;
import lombok.Getter;

import java.math.MathContext;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author hongda.li
 */
@Getter
public class ExpressionRunner {
    /**
     * 默认的执行器名称
     */
    public static final String DEFAULT_NAME = "defaultRunner";

    /**
     * 当前执行器的名称
     */
    private final String name;

    /**
     * 脚本引擎
     */
    private final AviatorEvaluatorInstance aviator;

    /**
     * 增强函数加载器
     */
    private final EnhancedFunctionLoader enhancedFunctionLoader;

    /**
     * 函数扫描器
     */
    private final List<FunctionScanner> scannerList = new ArrayList<>();

    /**
     * 初始化标识
     */
    private volatile boolean initialized = false;

    public ExpressionRunner() {
        this(DEFAULT_NAME);
    }

    public ExpressionRunner(String name) {
        this.name = name;
        this.aviator = AviatorEvaluator.newInstance();
        this.enhancedFunctionLoader = new EnhancedFunctionLoader(name, this.scannerList);
    }

    public synchronized void configure() {
        if (this.initialized) {
            return;
        }
        this.aviator.useLRUExpressionCache(1 << 10);
        this.aviator.setOption(Options.TRACE_EVAL, false);
        this.aviator.setOption(Options.SERIALIZABLE, false);
        this.aviator.setFunctionMissing(new FunctionFallback());
        this.aviator.setOption(Options.CAPTURE_FUNCTION_ARGS, true);
        this.aviator.setOption(Options.EVAL_MODE, EvalMode.INTERPRETER);
        this.aviator.setOption(Options.MAX_LOOP_COUNT, Integer.MIN_VALUE);
        this.aviator.addFunctionLoader(this.enhancedFunctionLoader.parse());
        this.aviator.setOption(Options.FEATURE_SET, Collections.emptySet());
        this.aviator.setOption(Options.MATH_CONTEXT, MathContext.DECIMAL128);
        this.aviator.setOption(Options.NIL_WHEN_PROPERTY_NOT_FOUND, true);
        this.aviator.setOption(Options.ENABLE_PROPERTY_SYNTAX_SUGAR, true);
        this.aviator.setOption(Options.PUT_CAPTURING_GROUPS_INTO_ENV, false);
        this.aviator.setOption(Options.OPTIMIZE_LEVEL, AviatorEvaluator.COMPILE);
        this.aviator.setOption(Options.ALLOWED_CLASS_SET, Collections.emptySet());
        this.aviator.setOption(Options.USE_USER_ENV_AS_TOP_ENV_DIRECTLY, true);
        this.aviator.removeFunctionLoader(ClassPathConfigFunctionLoader.getInstance());
        this.aviator.setOption(Options.ALWAYS_PARSE_INTEGRAL_NUMBER_INTO_DECIMAL, true);
        this.aviator.setOption(Options.ASSIGNABLE_ALLOWED_CLASS_SET, Collections.emptySet());
        this.aviator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, true);
        this.initialized = true;
    }

    /**
     * 添加函数扫描器
     *
     * @param scanner 函数扫描器
     * @return 链式调用
     */
    public ExpressionRunner addScanner(FunctionScanner scanner) {
        this.scannerList.add(scanner);
        return this;
    }

    /**
     * 执行表达式
     *
     * @param expression 表达式内容
     * @return 执行结果
     */
    public Object eval(String expression) {
        return this.eval(expression, Collections.emptyMap());
    }

    /**
     * 执行表达式
     *
     * @param expression 表达式内容
     * @param context    环境变量
     * @return 执行结果
     */
    public Object eval(String expression, Map<String, Object> context) {
        Assert.isTrue(this.initialized, "表达式执行器尚未初始化");
        return this.aviator.execute(DigestUtil.md5Hex(expression), expression, context, true);
    }
}
